﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using AutoMapper;
using Core;
using IglooCoder.Commons.WcfNhibernate;
using Infrastucture;
using WcfService1.DTO;
using Omu.ValueInjecter;

namespace WcfService1
{
    // NOTE: You can use the "Rename" command on the "Refactor" Coa to change the class name "CoaServices" in code, svc and config file together.
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    [NHibernateContext]
    public class CoaServices : ICoaServices
    {
        private readonly CoaRepository CoaRepository;
        private WcfSessionStorage _session;
        private MutasiHutangRepository mutasiHutangRepository;
        private MutasiPiutangRepository mutasiPiutangRepository;
        public CoaServices()
        {
            _session = new WcfSessionStorage();
            CoaRepository = new CoaRepository(_session);
            mutasiHutangRepository = new MutasiHutangRepository(_session);
            mutasiPiutangRepository = new MutasiPiutangRepository(_session);
        }

        #region ICoaServices Members

        public List<CoaDTO> GetList(int page, out long recordCount, string sortProperty = null, string sortType = "ASC")
        {
            var Coas = new List<COA>();
            var Results = new List<CoaDTO>();

            if (string.IsNullOrEmpty(sortProperty))
            {
                Coas = CoaRepository.GetDataPaged(page, 30).ToList();
            }
            else
            {
                Coas = CoaRepository.GetDataPaged(page, 30, sortProperty, sortType).ToList();
            }

            recordCount = CoaRepository.RecordCount;

            Coas.ForEach(x =>
                             {
                                 var CoaDto = new CoaDTO();
                                 CoaDto.ParentAccount = new CoaDTO();
                                 CoaDto.InjectFrom(x);
                                 if (x.ParentAccount != null) CoaDto.ParentAccount.InjectFrom(x.ParentAccount);
                                 //AutoMapper.Mapper.Map(x.ParentCoa, CoaDto.ParentCoa);
                                 Results.Add(CoaDto);
                             }
                );

            return Results;
        }

        public bool Save(CoaDTO CoaDTO)
        {
            bool res = false;
            try
            {
                CoaRepository.ExecuteTransactionNative(()=>
                                                           {
                                                               COA Coa = CoaRepository.GetDataOne(x => x.AccountNumber == CoaDTO.AccountNumber);
                                                               var user = new User();
                                                               if (Coa == null)
                                                               {
                                                                   Coa = new COA();
                                                                   CoaDTO.created_date = DateTime.Now;
                                                                   //AutoMapper.Mapper.Map(CoaDTO.created_by, user);
                                                                   //Coa.modified_by = null;
                                                               }
                                                               else
                                                               {
                                                                   CoaDTO.modified_date = DateTime.Now;
                                                                   //AutoMapper.Mapper.Map(CoaDTO.modified_by, user);
                                                               }
                                                               Mapper.Map(CoaDTO, Coa);
                                                               if (Coa.ParentAccount != null && String.IsNullOrEmpty(Coa.ParentAccount.AccountNumber))
                                                                   Coa.ParentAccount = null;
                                                               CoaRepository.SaveOrUpdate(Coa);
                                                               res = true;
                                                           });
              
            }
            catch (Exception)
            {
                res = false;
            }

            return res;
        }


        public bool Delete(CoaDTO CoaDto)
        {
            bool res;
            try
            {
                var Coa = CoaRepository.GetDataOne(x => x.AccountNumber == CoaDto.AccountNumber);
                CoaRepository.Delete(Coa);
                res = true;
            }
            catch (Exception)
            {
                res = false;
            }

            return res;
        }


        public List<CoaDTO> GetListByCriteria(Dictionary<String, Object> criteria, string expression, int page,
                                              out long recordCount)
        {
            var Coas = new List<COA>();
            var Results = new List<CoaDTO>();
            Coas = CoaRepository.GetDataPaged(criteria, expression, page, 30).ToList();
            recordCount = CoaRepository.RecordCount;
            Coas.ForEach(x =>
                             {
                                 var CoaDto = new CoaDTO();
                                 CoaDto.ParentAccount = new CoaDTO();
                                 CoaDto.InjectFrom(x);
                                 if (x.ParentAccount != null) CoaDto.ParentAccount.InjectFrom(x.ParentAccount);
                                 Results.Add(CoaDto);
                             }
                );

            return Results;
        }


        public List<CoaDTO> GetAllCoa()
        {
            List<COA> Coas = CoaRepository.GetDataList(x => x.ParentAccount != null) as List<COA>;
            var Results = new List<CoaDTO>();
            Coas.ForEach(x =>
                             {
                                 var CoaDto = new CoaDTO();
                                 CoaDto.ParentAccount = new CoaDTO();
                                 CoaDto.InjectFrom(x);
                                 if (x.AccountNumber.Length > 7) CoaDto.ParentAccount.InjectFrom(x.ParentAccount);
                                 Results.Add(CoaDto);
                             }
                );

            return Results;
        }


        public CoaDTO GetCoa(String AccountNumber)
        {
            COA Coa = CoaRepository.GetDataOne(x => x.AccountNumber == AccountNumber);
            var CoaDto = new CoaDTO();
            CoaDto.ParentAccount = new CoaDTO();
            CoaDto.InjectFrom(Coa);
            if (Coa.ParentAccount != null) CoaDto.ParentAccount.InjectFrom(Coa.ParentAccount);
            return CoaDto;
        }

        public List<CoaDTO> GetCoaList(string AccountNumber)
        {
            List<COA> Coas = CoaRepository.GetDataList(x => x.AccountNumber.Contains(AccountNumber)).ToList();
            var Results = new List<CoaDTO>();
            Coas.ForEach(x =>
                             {
                                 var CoaDto = new CoaDTO();
                                 CoaDto.ParentAccount = new CoaDTO();
                                 CoaDto.InjectFrom(x);
                                 if (x.ParentAccount != null) CoaDto.ParentAccount.InjectFrom(x.ParentAccount);
                                 Results.Add(CoaDto);
                             }
                );

            return Results;
        }


        public IEnumerable<CoaDTO> GetCoaKasBank()
        {
            List<COA> Coas = CoaRepository.GetDataList(x => x.GeneralInfo == "Kas & Bank").ToList();
            var Results = new List<CoaDTO>();
            Coas.ForEach(x =>
            {
                var CoaDto = new CoaDTO();
                CoaDto.ParentAccount = new CoaDTO();
                CoaDto.InjectFrom(x);
                if (x.ParentAccount != null) CoaDto.ParentAccount.InjectFrom(x.ParentAccount);
                Results.Add(CoaDto);
            }
                );

            return Results;
        }

        public IEnumerable<CoaDTO> GetCoaInventory()
        {
            List<COA> Coas = CoaRepository.GetDataList(x => x.GeneralInfo == "Inventory").ToList();
            var Results = new List<CoaDTO>();
            Coas.ForEach(x =>
            {
                var CoaDto = new CoaDTO();
                CoaDto.ParentAccount = new CoaDTO();
                CoaDto.InjectFrom(x);
                if (x.ParentAccount != null) CoaDto.ParentAccount.InjectFrom(x.ParentAccount);
                Results.Add(CoaDto);
            }
                );

            return Results;
        }

        public IEnumerable<CoaDTO> GetCoaHpp()
        {
            List<COA> Coas = CoaRepository.GetDataList(x => x.GeneralInfo == "Cogs").ToList();
            var Results = new List<CoaDTO>();
            Coas.ForEach(x =>
            {
                var CoaDto = new CoaDTO();
                CoaDto.ParentAccount = new CoaDTO();
                CoaDto.InjectFrom(x);
                if (x.ParentAccount != null) CoaDto.ParentAccount.InjectFrom(x.ParentAccount);
                Results.Add(CoaDto);
            }
                );

            return Results;
        }

        public IEnumerable<CoaDTO> GetCoaSales()
        {
            List<COA> Coas = CoaRepository.GetDataList(x => x.GeneralInfo == "Sales").ToList();
            var Results = new List<CoaDTO>();
            Coas.ForEach(x =>
            {
                var CoaDto = new CoaDTO();
                CoaDto.ParentAccount = new CoaDTO();
                CoaDto.InjectFrom(x);
                if (x.ParentAccount != null) CoaDto.ParentAccount.InjectFrom(x.ParentAccount);
                Results.Add(CoaDto);
            }
                );

            return Results;
        }


        public IEnumerable<CoaDTO> GetCoaSalesReturn()
        {
            List<COA> Coas = CoaRepository.GetDataList(x => x.GeneralInfo == "SalesReturn").ToList();
            var Results = new List<CoaDTO>();
            Coas.ForEach(x =>
            {
                var CoaDto = new CoaDTO();
                CoaDto.ParentAccount = new CoaDTO();
                CoaDto.InjectFrom(x);
                if (x.ParentAccount != null) CoaDto.ParentAccount.InjectFrom(x.ParentAccount);
                Results.Add(CoaDto);
            }
                );

            return Results;
        }


        public IEnumerable<CoaDTO> GetCoaExpense()
        {
            List<COA> Coas = CoaRepository.GetDataList(x => x.Category=="Expense").ToList();
            var Results = new List<CoaDTO>();
            Coas.ForEach(x =>
            {
                var CoaDto = new CoaDTO();
                CoaDto.ParentAccount = new CoaDTO();
                CoaDto.InjectFrom(x);
                if (x.ParentAccount != null) CoaDto.ParentAccount.InjectFrom(x.ParentAccount);
                Results.Add(CoaDto);
            }
                );

            return Results;
        }

        public void SaveSaldoAwalHutang(IEnumerable<SaldoAwalHutang> saldoAwalHutangs)
        {
            
            mutasiHutangRepository.ExecuteTransactionNative(()=>
            {
                mutasiHutangRepository.DeleteMutasiHutangByCoa(saldoAwalHutangs.FirstOrDefault().Coa.AccountNumber);
                foreach (var saldoAwalHutang in saldoAwalHutangs)
                {
                    var mutasiHutang = new MutasiHutang();
                    mutasiHutang.SaldoMasuk = saldoAwalHutang.Saldo;
                    mutasiHutang.SaldoSisa = saldoAwalHutang.Saldo;
                    mutasiHutang.SupplierId = saldoAwalHutang.Supplier.SupplierId;
                    mutasiHutang.Tanggal = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
                    mutasiHutang.Type = "SaldoAwal";
                    mutasiHutang.InvoiceNo = saldoAwalHutang.InvoiceNo;
                    mutasiHutang.Coa = saldoAwalHutang.Coa.AccountNumber;
                    mutasiHutang.ReferenceNumber = "SaldoAwal";
                    mutasiHutangRepository.SaveOrUpdate(mutasiHutang);
                }
          });
            
        }

        public void SaveSaldoAwalPiutang(IEnumerable<SaldoAwalPiutang> saldoAwalHutangs)
        {
          
            mutasiPiutangRepository.ExecuteTransactionNative(() =>
            {
                mutasiPiutangRepository.DeleteMutasiPiutangByCoa(saldoAwalHutangs.FirstOrDefault().Coa.AccountNumber);
                foreach (var saldoAwalHutang in saldoAwalHutangs)
                {
                    var mutasiHutang = new MutasiPiutang
                                           {
                                               SaldoMasuk = saldoAwalHutang.Saldo,
                                               SaldoSisa = saldoAwalHutang.Saldo,
                                               CustomerId = saldoAwalHutang.Customer.CustomerId,
                                               Tanggal =
                                                   new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day),
                                               Type = "SaldoAwal",
                                               InvoiceNo = saldoAwalHutang.InvoiceNo,
                                               Coa = saldoAwalHutang.Coa.AccountNumber,
                                               ReferenceNumber = "SaldoAwal"
                                           };
                    mutasiPiutangRepository.SaveOrUpdate(mutasiHutang);
                }
            });

        }


        public IEnumerable<SaldoAwalHutang> GetMutasiHutang(string accountNumber)
        {
            var supplierRepository = new SupplierRepository(_session);
            var mutasiHutangs = mutasiHutangRepository.GetDataList(x => x.Coa == accountNumber && x.Type == "SaldoAwal");
            List<SaldoAwalHutang> saldoAwalHutangs = new List<SaldoAwalHutang>();
            foreach (var mutasiHutang in mutasiHutangs)
            {
                var saldoAwalHutang = new SaldoAwalHutang();
                var supplier = supplierRepository.GetDataOne(x => x.SupplierId == mutasiHutang.SupplierId);
                saldoAwalHutang.Supplier = (SupplierDTO) new SupplierDTO().InjectFrom(supplier);
                saldoAwalHutang.InvoiceNo = mutasiHutang.InvoiceNo;
                saldoAwalHutang.Saldo = mutasiHutang.SaldoSisa;
                saldoAwalHutang.Coa = new CoaDTO() {AccountNumber = mutasiHutang.Coa};
                saldoAwalHutangs.Add(saldoAwalHutang);
            }
            return saldoAwalHutangs;
        }

        public IEnumerable<SaldoAwalPiutang> GetMutasiPiutang(string accountNumber)
        {
            var mutasiPiutangs = mutasiPiutangRepository.GetDataList(x => x.Coa == accountNumber && x.Type == "SaldoAwal");
            var customerRepository = new CustomerRepository(_session);
            List<SaldoAwalPiutang> saldoAwalPiutangs = new List<SaldoAwalPiutang>();
            foreach (var mutasiPiutang in mutasiPiutangs)
            {
                var saldoAwalPiutang = new SaldoAwalPiutang();
                var customer = customerRepository.GetDataOne(x => x.CustomerId == mutasiPiutang.CustomerId);
                saldoAwalPiutang.Customer = (CustomerDTO) new CustomerDTO().InjectFrom(customer);
                saldoAwalPiutang.InvoiceNo = mutasiPiutang.InvoiceNo;
                saldoAwalPiutang.Saldo = mutasiPiutang.SaldoSisa;
                saldoAwalPiutang.Coa = new CoaDTO() { AccountNumber = mutasiPiutang.Coa };
                saldoAwalPiutangs.Add(saldoAwalPiutang);
            }
            return saldoAwalPiutangs;
        } 
        
        #endregion
    }
}